﻿using System;
using System.Collections;
using System.Collections.Generic;

namespace LoRel
{
    public class FieldDeclaration {
        private String m_Name;
        private Type m_Type;

        public FieldDeclaration( string name, Type type ) {
            m_Name = name;
            m_Type = type;
        }

        public string Name { get { return m_Name; } }
        public Type Type { get { return m_Type; } }
    }

    public class ColumnDeclaration {
        private String m_Table;
        private FieldDeclaration m_Field;
        public ColumnDeclaration( string table, FieldDeclaration field ) {
            m_Table = table;
            m_Field = field;
        }

        public string Table { get { return m_Table; } }
        public FieldDeclaration Field { get { return m_Field; } }
        
        public string Name {
            get { return m_Field.Name; } }

        public Type Type {
            get { return m_Field.Type; } }
    }

    public class KeyDeclaration {
        private String m_Table;
        private ColumnDeclaration[] m_Columns;

        public KeyDeclaration( string table, ColumnDeclaration[] columns ) {
            m_Table = table;
            m_Columns = columns;
        }

        public string Table { get { return m_Table; } }
        public ColumnDeclaration[] Columns { get { return m_Columns; } }
    }

    public class ColumnReference {
        private ColumnDeclaration m_Column;
        public ColumnReference( ColumnDeclaration column ) { m_Column = column; }

        public string Table {
            get { return m_Column.Table; } }

        public ColumnDeclaration Column { get { return m_Column; } }

        public FieldDeclaration Field {
            get { return m_Column.Field; } }

        public string Name {
            get { return m_Column.Name; } }

        public Type Type {
            get { return m_Column.Type; } }
    }

    public class KeyReference {
        private String m_Table;
        private ColumnSet m_Columns;
        public KeyReference( string table, ColumnSet columns ) {
            m_Table = table;
            m_Columns = columns;
        }

        public string Table { get { return m_Table; } }
        public ColumnSet Columns { get { return m_Columns; } }
    }

    public class TableReference {
        private String m_Table;
        private ColumnSet m_Columns;
        private KeyReference m_Keys;
        private Dictionary< String, ColumnReference > m_ColumnReferences;

        public TableReference(string table, ColumnSet columns, KeyReference keys)
        {
            m_Table = table;
            m_Columns = columns;
            m_Keys = keys;

            m_ColumnReferences = new Dictionary< string, ColumnReference >();
            foreach( ColumnReference column in m_Columns ) {
                m_ColumnReferences.Add( column.Name, column );
            }
        }

        public ColumnReference GetColumn( String name ) { 
            ColumnReference reference;
            if( m_ColumnReferences.TryGetValue( name, out reference ) ) {
                return reference;
            }
            const String FORMAT = "Column '{0}' not contained in Table '{1}'";
            throw new ArgumentException("name", String.Format( FORMAT, name, m_Table ));
        }

        public string Table { get { return m_Table; } }
        public ColumnSet Columns { get { return m_Columns; } }
        public KeyReference Keys { get { return m_Keys; } }
    }

    public class ColumnSet : IEnumerable<ColumnReference> {
        private readonly List< ColumnReference > m_Columns;

        public ColumnSet( IEnumerable< ColumnReference > columns ) {
            m_Columns = new List< ColumnReference >( columns );
        }


        public ColumnReference this[ int index ] {
            get { return m_Columns[ index ]; }
        }

        public int Count { get { return m_Columns.Count; }
            set { throw new NotImplementedException(); } }

        public bool Equals( ColumnSet rhs ) {
            if (m_Columns.Count != rhs.m_Columns.Count) return false;
            for (int i = 0; i < m_Columns.Count; i++) {
                if (m_Columns[i] != rhs.m_Columns[i]) return false;
            }
            return true;
        }
        public override bool Equals(object obj) {
            ColumnSet rhs = obj as ColumnSet;
            if (rhs != null) Equals( rhs );
            return base.Equals(obj);
        }

        public override int GetHashCode() {
            
            unchecked {
                int result = 0;
                foreach( ColumnReference col in m_Columns ) {
                    result = ( result*397 ) ^ col.Name.GetHashCode();
                }
                return result;
            }
        }
        public IEnumerator<ColumnReference> GetEnumerator() { return m_Columns.GetEnumerator(); }
        IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }

    }
}
